#include "Platform/Platform.h"


#include "GlobalClass.h"


#include <QPixmap>
#include <QPainter>
#include <QHash>

quint32 intRand()
{
    return QRandomGenerator::global()->generate();
}

quint64 longRand()
{
    return QRandomGenerator::global()->generate64();
}

quint32 Random(quint32 n1, quint32 n2)
{
    return QRandomGenerator::global()->bounded(n1, n2);
}

/*
qint32 intRand()
{
    if(RAND_MAX <= 0x7fff)
    {
        qint32 r1 = qrand();
        return (r1 << 16) + (qrand() << 1) + (qrand() % 2);
    }
    else    //0x7fffffff
        return qrand();
}

qint64 longRand()
{
    if(RAND_MAX <= 0x7fff)
    {
        qint64 r1 = intRand();
        qint64 r2 = intRand();
        return (r1 << 32) + (r2 << 1) + (qrand() % 2);
    }
    else if(RAND_MAX <= 0x7fffffff)
    {
        qint64 r1 = qrand();
        qint64 r2 = qrand();
        return (r1 << 32) + (r2 << 1) + (qrand() % 2);
    }
    else    // > 0x7fffffff
        return qrand();

}

qint32 Random(qint32 n1, qint32 n2)
{
    if(n1==n2)return n1;
    else if(n2<n1)
    {
        n1=n1+n2;
        n2=n1-n2;
        n1=n1-n2;
    }
    return (intRand() % ( n2 - n1 )) + n1;
    //int value=minValue+int((maxValue-minValue)*(rand()/(float)RAND_MAX));
}

*/

////////////////////////////////////////////////

qint32 RandTarget(quint32 n, quint32 m)        //m分之n
{
    if(n > m || n < 0)return -1;    //不符合
    if(intRand() % m < n)return 1;    //命中
    return 0;
}

//n1到n2产生n个不同数字返回到arr

//使用hash
bool GetDifferentNumber(qint32 n1, qint32 n2, void *arr, int n, int elementSize)
{
    if(abs(n2 - n1) < n)
        return false;

    qint32 number;
    QHash<qint32, bool> hash;

    for(qint32 i = 0; i < n;)
    {
        number = Random(n1,n2);
        if(!hash.contains(number)) {
            hash[number] = true;
            memcpy((char*)arr + (i * elementSize), &number, elementSize);
            i++;
        }
    }
    return true;
}


//简单的对比
void GetDifferentNumber2(qint32 n1, qint32 n2, qint32 arr[],qint32 n)
{
    for(qint32 i = 0; i < n; i++)
    {
        arr[i] = Random(n1, n2);
        for(qint32 j = 0; j < i; j++)
        {
            if(arr[j] == arr[i])
            {
                i--;
                break;
            }
        }
    }
}

#include <random>
double lms_DefaultRandom(double mean, double standardDeviation, int type)
{
    double number;
    static std::default_random_engine generator(time(0));

    if(type > 0)
    {
        //std::default_random_engine generator(type);     //产生器
        std::normal_distribution<double> distribution(mean, standardDeviation);

        number = distribution(generator);
    }
    else if(type == 0)
    {
        //std::default_random_engine generator;
        std::normal_distribution<double> distribution(mean, standardDeviation);

        number = distribution(generator);
    }
    else
    {
        //std::default_random_engine generator(time(0));
        std::normal_distribution<double> distribution(mean, standardDeviation);

        number = distribution(generator);
    }
    //std::lround(number);

    //qDebug() << generator.min() << generator.max();

    return number;
}

double lms_DefaultRandom(double mean, double standardDeviation, double min, double max, int type)
{
    double number = lms_DefaultRandom(mean, standardDeviation, type);
    if(number < min)
        return min;
    if(number > max)
        return max;
    return number;
}





//以空间换时间
/*
arr :数组名
n  :给定的数组长度
转移数组中的数据
*/
void GetDifferentNumber5(qint32 arr[],qint32 n)
{
    qint32 sn = n, index;
    qint32 *pfrom = new qint32[sn];
    for(qint32 i = 0; i < sn; i++)
        *(pfrom + i) = i + 1 ;    //设置pfrom数组为1~sn+1

    for(qint32 k = 0;k < sn;)
    {
        index = rand() % sn;
        if(*(pfrom+index) != 0)
        {   //从源数据pfrom取，每取一个将其置为0，直至pfrom中所有元素都为0
            *(arr+k) = pfrom[index];
            pfrom[index] = 0;
            k++;
        }
    }
    delete[] pfrom;
}

void GetDifferentNumber6(qint32 n,qint32 arr[])
{
    qint32 i,m;
    memset(arr,0,sizeof(qint32) * n);
    for(i = 1; i <= n; i++)    //将 1 ~ n 打乱并放入 arr 中
    {
        while(arr[m = rand() % n]);        //找到a[m]为0的
        arr[m]=i;
    }
}



int nonASCIICount(QString str)
{
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");//GB18030 UTF-8
    return (codec->fromUnicode(str).length() - str.length()) / 2;
}


#include <QJSValue>
QString JSon2String(QVariant data)
{
    //qDebug() << "!!!!!!!!!!" << data.type() << data << data.userType() << data.typeName();

    //.type()：返回QVariant::Type
    //.userType()：返回TypeID(int)
    //.typeName()：返回类型名(const char*)
    if(data.type() == QVariant::String)
        return data.toString();

    //if(data.userType() == qMetaTypeId<QJSValue>())    //1075
    if(data.canConvert<QJSValue>())
    {
        //QJSValue jsValue = data.value<QJSValue>();
        //QJsonDocument document = QJsonDocument::fromVariant(jsValue.toVariant());
        //return document.toJson(QJsonDocument::Compact);
        return QJsonDocument::fromVariant(data.value<QJSValue>().toVariant()).toJson(QJsonDocument::Compact);
    }

    if(data.canConvert<QVariantMap>() || data.canConvert<QVariantList>())
        return QJsonDocument::fromVariant(data).toJson(QJsonDocument::Compact);

    //QJsonDocument document = QJsonDocument::fromVariant(data);
    return QJsonDocument::fromVariant(data).toJson(QJsonDocument::Compact);
}

QVariant String2Json(QString json)
{
    QByteArray baJson = json.toLocal8Bit();
    //QByteArray baJson = json.toLatin1();
    //QByteArray baJson = json.toUtf8();
    QJsonParseError jsonError;
    QJsonDocument document = QJsonDocument::fromJson(baJson, &jsonError);  // 转化为 JSON 文档
    if (!document.isNull() && (jsonError.error == QJsonParseError::NoError))  // 解析未发生错误
    {
        return document.toVariant();
    }
    return QVariant();
}



////////////////////////////////////////////////




#include <QTimer>
#include <QEventLoop>
#include <QCoreApplication>

//
void Wait(int msec, QEventLoop::ProcessEventsFlags flags)
{
    QEventLoop eventloop;
    QTimer::singleShot(msec, &eventloop, SLOT(quit()));
    eventloop.exec(flags);
}


void Wait1(int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while(QTime::currentTime() < dieTime)
    {
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);    //手动派发事件
    }
}

#include <QElapsedTimer>
void Wait2(int msec)
{
    QElapsedTimer t;
    t.start();
    while(t.elapsed() < msec)
    {
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);    //手动派发事件
    }
}


////////////////////////////////////////////////





#include <QFileInfo>
#include <QDir>

bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
{
    QDir sourceDir(fromDir);
    QDir targetDir(toDir);
    if(!targetDir.exists()){    /**< 如果目标目录不存在，则进行创建 */
        if(!targetDir.mkdir(targetDir.absolutePath()))
        {
            qWarning() << "mkdir FAIL:" << targetDir << targetDir.absolutePath();
            return false;
        }
    }

    QFileInfoList fileInfoList = sourceDir.entryInfoList();
    //QFileInfoList folders = qrcExamplesDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot);
    //QFileInfoList files = qrcExampleDir.entryInfoList(QDir::Files);
    foreach(QFileInfo fileInfo, fileInfoList){
        if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
            continue;

        if(fileInfo.isDir()){    /**< 当为目录时，递归的进行copy */
            if(!copyDirectoryFiles(fileInfo.filePath(),
                targetDir.filePath(fileInfo.fileName()),
                coverFileIfExist))
            {
                return false;
            }
        }
        else{            /**< 当允许覆盖操作时，将旧文件进行删除操作 */
            if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
                targetDir.remove(fileInfo.fileName());
            }

            /// 进行文件copy
            if(!QFile::copy(fileInfo.filePath(),
                targetDir.filePath(fileInfo.fileName()))) {
                {
                    qWarning() << "copy Failed:" << fileInfo.filePath() << targetDir.filePath(fileInfo.fileName());
                    return false;
                }
            }

            QFile::setPermissions(targetDir.filePath(fileInfo.fileName()),
                                  QFileDevice::ReadOwner | QFileDevice::WriteOwner |
                                  QFileDevice::ReadUser  | QFileDevice::WriteUser  |
                                  QFileDevice::ReadGroup | QFileDevice::WriteGroup |
                                  QFileDevice::ReadOther | QFileDevice::WriteOther
                                  );
        }
    }

    return true;
}

#include <QMessageBox>
bool copyFileAndSetPermissions(const QString& filename, QFileDevice::Permissions permissionSpec)
{
    QFileInfo fi(filename);
    //fi.setFile(filename);
    if(!fi.isFile())        //不是文件
    {
        if(!QFile::copy(QString("assets:/%1").arg(filename), filename))
        {
            qWarning() << "[!WARNING]copy FAIL:" << filename;
            //QMessageBox::critical(nullptr,"错误",QString("copy %1 FAIL!").arg(filename));
            return false;
        }

        if(QFile::setPermissions(filename, permissionSpec))
        {
            /*QFile::setPermissions(baseFolderPath(Examples) + QDir::separator() + folderName + QDir::separator() + fileName,
                                  QFileDevice::ReadOwner | QFileDevice::WriteOwner |
                                  QFileDevice::ReadUser  | QFileDevice::WriteUser  |
                                  QFileDevice::ReadGroup | QFileDevice::WriteGroup |
                                  QFileDevice::ReadOther | QFileDevice::WriteOther
                                  );*/
            qDebug() << "setPermissions success:" << filename;
        }
        else
        {
            qWarning() << "[!WARNING]setPermissions FAIL:" << filename;
            //QMessageBox::warning(nullptr,"警告",QString("setPermissions %1 FAIL!").arg(filename));
            return false;
        }
    }
    return true;
}


void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    static QMutex mutex;
    QString text;

    switch(type)
    {
    case QtDebugMsg:
        text = QString("Debug:");
        break;

    case QtWarningMsg:
        text = QString("Warning:");
        break;

    case QtCriticalMsg:
        text = QString("Critical:");
        break;

    case QtFatalMsg:
        text = QString("Fatal:");
        break;

    default:
        text = QString("Unkown:");
        break;
    }


    QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line);
    QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
    QString current_date = QString("(%1)").arg(current_date_time);
    QString message = QString("%1 %2 %3 %4").arg(text).arg(context_info).arg(msg).arg(current_date);


    mutex.lock();

    QFile file(QString(FIXLOCALPATH_W("log_%1.txt")).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd")));
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << "\r\n";
    file.flush();
    //text_stream.setDevice(nullptr);
    file.close();

    mutex.unlock();
}



/*
QString("<center><h1>Press: (%1, %2)</h1></center>")
    .arg(QString::number(event->x()),
         QString::number(event->y())));

QString msg;
msg.sprintf("<center><h1>Release: (%d, %d)</h1></center>",
    event->x(), event->y());
*/

QPixmap Ltrans(QPixmap &pix1, int Alpha)
{
    QPixmap temp(pix1.size());
    temp.fill(Qt::transparent);

    QPainter p1(&temp);
    p1.setCompositionMode(QPainter::CompositionMode_Source);
    p1.drawPixmap(0, 0, pix1);
    p1.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    p1.fillRect(temp.rect(), QColor(0, 0, 0, Alpha));
    p1.end();

    return temp;
}



void showHex(char *data,unsigned int length)
{
    QString t,str;
    unsigned int i = 0;
    for(; i < length; i++)
    {
        t.asprintf("0x%x(%c),",*(data + i),*(data + i));
        str += t;
    }
    qDebug() << str;
}

void showHex(QByteArray b)
{
    QString t,str;
    int i = 0;
    for(; i < b.length(); i++)
    {
        t.asprintf("0x%x(%c),",*(b.data() + i),*(b.data() + i));
        str += t;
    }
    qDebug() << str;
}










////////////////////生产者模式类///////////////////
__ProducerData::__ProducerData()
{
    type = 0;
    sender = nullptr;
}
__ProducerData::~__ProducerData()
{
    Release();
}
void __ProducerData::Release()
{}

ProducerModel::ProducerModel(){}
ProducerModel::~ProducerModel()
{
    resetDataList();
}







#include <QThread>
LongTask::LongTask(/*QObject *parent*/)//: QObject(parent)
{
    m_bDestroyed = false;

    m_pThread = new QThread;

    /*connect(m_pThread, &QThread::started, this, [=](){
        qDebug()<<"init ThreadId:"<<QThread::currentThreadId();

        this->_init();
    });
    connect(this, &LongTask::destroyed, this, [=](){
        qDebug()<<"destroy ThreadId:"<<QThread::currentThreadId();

        m_pThread->quit();
    }
    //, Qt::QueuedConnection
    );
    connect(m_pThread, &QThread::finished, this, [=](){
        qDebug()<<"finish ThreadId:"<<QThread::currentThreadId();

        m_pThread->deleteLater();
    }
    //, Qt::QueuedConnection
    );*/
    connect(m_pThread, &QThread::started, this, &LongTask::_init);
    connect(this, &LongTask::destroyed, m_pThread, &QThread::quit, Qt::DirectConnection);
    //connect(this, SIGNAL(destroyed(QObject*)), m_pThread, SLOT(quit()), Qt::QueuedConnection);
    connect(m_pThread, &QThread::finished, m_pThread, &QThread::deleteLater);

    this->moveToThread(m_pThread);
    m_pThread->start();
}

LongTask::~LongTask()
{
    if(m_bDestroyed)
        return;

    destroy();
    qDebug() << "LongTask Released";
}

int LongTask::_init()
{
    return 0;
}
int LongTask::_release()
{
    //m_pThread->quit();
    m_bDestroyed = true;

    return 0;
}

int LongTask::destroy()
{
    QMetaObject::invokeMethod(this, "_release"
                              ,Qt::AutoConnection
                              //,Q_RETURN_ARG(QVariant, v)
                              //,Q_ARG(QByteArray, m_Server.m_IOCPModel.newSendData())
                              );
    this->deleteLater();
    return 0;
}

QThread* LongTask::thread()
{
    return m_pThread;
}



/*
WorkerThread::WorkerThread()//QObject *parent)//: QObject(parent)
{
    connect(this, &QThread::finished, this, &QThread::deleteLater);

    this->moveToThread(this);
    start();
}

WorkerThread::~WorkerThread()
{
    qDebug() << "WorkerThread Released";
}

int WorkerThread::init()
{
    return 0;
}

int WorkerThread::release()
{
    this->quit();
    return 0;
}
*/



#include <QUrl>

void FileWriteTask::WriteDataToFile(QIODevice::OpenMode mode, const QString filename, const QByteArray baData)
{
    QDir dir(QFileInfo(filename).absolutePath());
    if(!dir.exists())    /**< 如果目标目录不存在，则进行创建 */
        if(!dir.mkpath(dir.absolutePath()))
            return;

    QFile file(filename);
    file.open(mode);
    QDataStream ds(&file);
    ds << baData;
    //ds << QThread::currentThreadId();

    file.flush();
    //ds.setDevice(nullptr);
    file.close();
}

void FileWriteTask::WriteTextToFile(QIODevice::OpenMode mode, const QString filename, const QString text)
{
    QDir dir(QFileInfo(filename).absolutePath());
    if(!dir.exists())    /**< 如果目标目录不存在，则进行创建 */
        if(!dir.mkpath(dir.absolutePath()))
            return;

    QFile file(filename);
    file.open(mode);
    QTextStream text_stream(&file);
    text_stream << text;
    //text_stream << QThread::currentThreadId() << "\r\n";

    file.flush();
    //text_stream.setDevice(nullptr);
    file.close();
}





void FileWriteTask2::WriteDataToFile(QIODevice::OpenMode mode, const QString filename, const QByteArray baData)
{
    QVariantList list;
    list << QVariant::fromValue<QIODevice::OpenMode>(mode);
    list << filename;
    list << baData;

    QMetaObject::invokeMethod(m_LongTask,"runCallBack"    //线程中执行这个函数，函数会回调testFunc
                              ,Qt::AutoConnection
                              //,Q_RETURN_ARG(QVariant, v)
                              ,Q_ARG(void*, (void*)WriteToFileCallback)
                              ,Q_ARG(QVariant, (QVariant)list)
                              ,Q_ARG(int, 1)
                              );

}

void FileWriteTask2::WriteTextToFile(QIODevice::OpenMode mode, const QString filename, const QString text)
{
    QVariantList list;
    list << QVariant::fromValue<QIODevice::OpenMode>(mode);
    list << filename;
    list << text;

    QMetaObject::invokeMethod(m_LongTask,"runCallBack"    //线程中执行这个函数，函数会回调testFunc
                              ,Qt::AutoConnection
                              //,Q_RETURN_ARG(QVariant, v)
                              ,Q_ARG(void*, (void*)WriteToFileCallback)
                              ,Q_ARG(QVariant, (QVariant)list)
                              ,Q_ARG(int, 2)
                              );

}

QVariant FileWriteTask2::WriteToFileCallback(QVariant v, int id)
{
    QVariantList list = v.toList();
    QIODevice::OpenMode mode = list.takeFirst().value<QIODevice::OpenMode>();
    QString filename = list.takeFirst().toString();
    if(id == 1)
    {
        QDir dir(QFileInfo(filename).absolutePath());
        if(!dir.exists())    /**< 如果目标目录不存在，则进行创建 */
            if(!dir.mkpath(dir.absolutePath()))
                return id;

        QFile file(filename);
        file.open(mode);
        QDataStream ds(&file);
        ds << list.takeFirst().toByteArray();
        //ds << QThread::currentThreadId();

        file.flush();
        //ds.setDevice(nullptr);
        file.close();
    }
    else if(id == 2)
    {
        QDir dir(QFileInfo(filename).absolutePath());
        if(!dir.exists())    /**< 如果目标目录不存在，则进行创建 */
            if(!dir.mkpath(dir.absolutePath()))
                return id;

        QFile file(filename);
        file.open(mode);
        QTextStream text_stream(&file);
        text_stream << list.takeFirst().toString();
        //text_stream << QThread::currentThreadId() << "\r\n";

        file.flush();
        //text_stream.setDevice(nullptr);
        file.close();
    }
    qDebug() << "worker thread:" << QThread::currentThreadId() << v << id;
    return id;     //返回值会传到步骤2的结果处理函数中
}
